package com.sun.mail.util;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class SocketFetcher {
    public static Socket getSocket(String host, int port, Properties props, String prefix, boolean useSSL) throws IOException {
        boolean fb;
        String sfClass;
        int sfPort;
        SocketFactory sf;
        String sfPortStr;
        int to;
        Throwable ex;
        if (prefix == null) {
            prefix = "socket";
        }
        if (props == null) {
            props = new Properties();
        }
        String s = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".connectiontimeout").toString(), null);
        int cto = -1;
        if (s != null) {
            try {
                cto = Integer.parseInt(s);
            } catch (NumberFormatException e) {
            }
        }
        Socket socket = null;
        String timeout = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".timeout").toString(), null);
        String localaddrstr = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".localaddress").toString(), null);
        InetAddress localaddr = null;
        if (localaddrstr != null) {
            localaddr = InetAddress.getByName(localaddrstr);
        }
        String localportstr = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".localport").toString(), null);
        int localport = 0;
        if (localportstr != null) {
            try {
                localport = Integer.parseInt(localportstr);
            } catch (NumberFormatException e2) {
            }
        }
        String fallback = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".socketFactory.fallback").toString(), null);
        if (fallback != null) {
            if (fallback.equalsIgnoreCase("false")) {
                fb = false;
                sfClass = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".socketFactory.class").toString(), null);
                sfPort = -1;
                sf = getSocketFactory(sfClass);
                if (sf != null) {
                    sfPortStr = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".socketFactory.port").toString(), null);
                    if (sfPortStr != null) {
                        try {
                            sfPort = Integer.parseInt(sfPortStr);
                        } catch (NumberFormatException e3) {
                        }
                    }
                    if (sfPort == -1) {
                        sfPort = port;
                    }
                    socket = createSocket(localaddr, localport, host, sfPort, cto, sf, useSSL);
                }
                if (socket == null) {
                    socket = createSocket(localaddr, localport, host, port, cto, null, useSSL);
                }
                to = -1;
                if (timeout != null) {
                    try {
                        to = Integer.parseInt(timeout);
                    } catch (NumberFormatException e4) {
                    }
                }
                if (to >= 0) {
                    socket.setSoTimeout(to);
                }
                configureSSLSocket(socket, props, prefix);
                return socket;
            }
        }
        fb = true;
        sfClass = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".socketFactory.class").toString(), null);
        sfPort = -1;
        try {
            sf = getSocketFactory(sfClass);
            if (sf != null) {
                sfPortStr = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".socketFactory.port").toString(), null);
                if (sfPortStr != null) {
                    sfPort = Integer.parseInt(sfPortStr);
                }
                if (sfPort == -1) {
                    sfPort = port;
                }
                socket = createSocket(localaddr, localport, host, sfPort, cto, sf, useSSL);
            }
        } catch (SocketTimeoutException sex) {
            throw sex;
        } catch (Exception e5) {
            ex = e5;
            if (!fb) {
                if (ex instanceof InvocationTargetException) {
                    Throwable t = ((InvocationTargetException) ex).getTargetException();
                    if (t instanceof Exception) {
                        ex = (Exception) t;
                    }
                }
                if (ex instanceof IOException) {
                    throw ((IOException) ex);
                }
                IOException iOException = new IOException("Couldn't connect using \"" + sfClass + "\" socket factory to host, port: " + host + ", " + sfPort + "; Exception: " + ex);
                iOException.initCause(ex);
                throw iOException;
            }
        }
        if (socket == null) {
            socket = createSocket(localaddr, localport, host, port, cto, null, useSSL);
        }
        to = -1;
        if (timeout != null) {
            to = Integer.parseInt(timeout);
        }
        if (to >= 0) {
            socket.setSoTimeout(to);
        }
        configureSSLSocket(socket, props, prefix);
        return socket;
    }

    private static Socket createSocket(InetAddress localaddr, int localport, String host, int port, int cto, SocketFactory sf, boolean useSSL) throws IOException {
        Socket socket;
        if (sf != null) {
            socket = sf.createSocket();
        } else if (useSSL) {
            socket = SSLSocketFactory.getDefault().createSocket();
        } else {
            socket = new Socket();
        }
        if (localaddr != null) {
            socket.bind(new InetSocketAddress(localaddr, localport));
        }
        if (cto >= 0) {
            socket.connect(new InetSocketAddress(host, port), cto);
        } else {
            socket.connect(new InetSocketAddress(host, port));
        }
        return socket;
    }

    private static SocketFactory getSocketFactory(String sfClass) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        if (sfClass == null || sfClass.length() == 0) {
            return null;
        }
        ClassLoader cl = getContextClassLoader();
        Class clsSockFact = null;
        if (cl != null) {
            try {
                clsSockFact = cl.loadClass(sfClass);
            } catch (ClassNotFoundException e) {
            }
        }
        if (clsSockFact == null) {
            clsSockFact = Class.forName(sfClass);
        }
        return (SocketFactory) clsSockFact.getMethod("getDefault", new Class[0]).invoke(new Object(), new Object[0]);
    }

    public static Socket startTLS(Socket socket, Properties props, String prefix) throws IOException {
        String host = socket.getInetAddress().getHostName();
        int port = socket.getPort();
        try {
            SSLSocketFactory ssf;
            SocketFactory sf = getSocketFactory(props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".socketFactory.class").toString(), null));
            if (sf == null || !(sf instanceof SSLSocketFactory)) {
                ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
            } else {
                ssf = (SSLSocketFactory) sf;
            }
            socket = ssf.createSocket(socket, host, port, true);
            configureSSLSocket(socket, props, prefix);
            return socket;
        } catch (Exception e) {
            Exception ex = e;
            if (ex instanceof InvocationTargetException) {
                Throwable t = ((InvocationTargetException) ex).getTargetException();
                if (t instanceof Exception) {
                    ex = (Exception) t;
                }
            }
            if (ex instanceof IOException) {
                throw ((IOException) ex);
            }
            IOException ioex = new IOException("Exception in startTLS: host " + host + ", port " + port + "; Exception: " + ex);
            ioex.initCause(ex);
            throw ioex;
        }
    }

    private static void configureSSLSocket(Socket socket, Properties props, String prefix) {
        if (socket instanceof SSLSocket) {
            SSLSocket sslsocket = (SSLSocket) socket;
            String protocols = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".ssl.protocols").toString(), null);
            if (protocols != null) {
                sslsocket.setEnabledProtocols(stringArray(protocols));
            } else {
                sslsocket.setEnabledProtocols(new String[]{"TLSv1"});
            }
            String ciphers = props.getProperty(new StringBuilder(String.valueOf(prefix)).append(".ssl.ciphersuites").toString(), null);
            if (ciphers != null) {
                sslsocket.setEnabledCipherSuites(stringArray(ciphers));
            }
        }
    }

    private static String[] stringArray(String s) {
        StringTokenizer st = new StringTokenizer(s);
        List tokens = new ArrayList();
        while (st.hasMoreTokens()) {
            tokens.add(st.nextToken());
        }
        return (String[]) tokens.toArray(new String[tokens.size()]);
    }

    private static ClassLoader getContextClassLoader() {
        return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                ClassLoader cl = null;
                try {
                    cl = Thread.currentThread().getContextClassLoader();
                } catch (SecurityException e) {
                }
                return cl;
            }
        });
    }
}
